import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import * as THREE from 'three';

class ModelLoader {
    constructor() {
        // 初始化GLTF加载器
        this.gltfLoader = new GLTFLoader();
        
        // 初始化DRACO解码器
        this.dracoLoader = new DRACOLoader();
        this.dracoLoader.setDecoderPath('/draco/');
        this.gltfLoader.setDRACOLoader(this.dracoLoader);

        // 缓存已加载的模型
        this.cache = new Map();
    }

    /**
     * 加载模型
     * @param {string} url - 模型URL
     * @param {Object} options - 加载选项
     * @returns {Promise<THREE.Group>} 加载后的模型
     */
    async load(url, options = {}) {
        try {
            // 检查缓存
            if (this.cache.has(url)) {
                const cachedModel = this.cache.get(url);
                return this.cloneModel(cachedModel);
            }

            // 加载模型
            const gltf = await this.loadModel(url);
            
            // 处理模型
            const model = this.processModel(gltf, options);
            
            // 缓存模型
            this.cache.set(url, model);
            
            return this.cloneModel(model);
        } catch (error) {
            console.error('模型加载失败:', error);
            throw error;
        }
    }

    /**
     * 加载模型文件
     * @private
     */
    loadModel(url) {
        return new Promise((resolve, reject) => {
            this.gltfLoader.load(
                url,
                (gltf) => resolve(gltf),
                (progress) => {
                    console.log('加载进度:', (progress.loaded / progress.total * 100) + '%');
                },
                (error) => reject(error)
            );
        });
    }

    /**
     * 处理加载后的模型
     * @private
     */
    processModel(gltf, options) {
        const model = gltf.scene;

        // 应用缩放
        if (options.scale) {
            model.scale.copy(options.scale);
        }

        // 应用位置
        if (options.position) {
            model.position.copy(options.position);
        }

        // 应用旋转
        if (options.rotation) {
            model.rotation.copy(options.rotation);
        }

        // 设置阴影
        model.traverse((node) => {
            if (node.isMesh) {
                node.castShadow = true;
                node.receiveShadow = true;
                
                // 优化材质
                if (node.material) {
                    node.material = this.optimizeMaterial(node.material);
                }
            }
        });

        // 提取动画
        const animations = new Map();
        if (gltf.animations && gltf.animations.length > 0) {
            gltf.animations.forEach(animation => {
                animations.set(animation.name, animation);
            });
        }

        return {
            model,
            animations
        };
    }

    /**
     * 优化材质
     * @private
     */
    optimizeMaterial(material) {
        const newMaterial = material.clone();
        
        // 设置基础材质属性
        newMaterial.roughness = 0.7;
        newMaterial.metalness = 0.3;
        
        // 优化纹理设置
        if (newMaterial.map) {
            newMaterial.map.anisotropy = 16;
            newMaterial.map.encoding = THREE.sRGBEncoding;
        }

        return newMaterial;
    }

    /**
     * 克隆模型
     * @private
     */
    cloneModel(originalModel) {
        const model = originalModel.model.clone();
        const animations = new Map(originalModel.animations);
        
        return {
            model,
            animations
        };
    }

    /**
     * 释放模型资源
     */
    dispose() {
        this.cache.forEach((model) => {
            model.model.traverse((node) => {
                if (node.isMesh) {
                    node.geometry.dispose();
                    if (Array.isArray(node.material)) {
                        node.material.forEach(material => material.dispose());
                    } else {
                        node.material.dispose();
                    }
                }
            });
        });
        
        this.cache.clear();
        this.dracoLoader.dispose();
    }
}

export const modelLoader = new ModelLoader(); 